package pt.um.jspecput.specifications;

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.util.ArrayList;

import javax.validation.constraints.Pattern;

import org.databene.benerator.anno.InvocationCount;
import org.databene.feed4junit.Feeder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import com.google.common.collect.Lists;

import daikon.PptMap;

@RunWith(Feeder.class)
public class DaikonIntegrationTest {

    private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
    private final ByteArrayOutputStream errContent = new ByteArrayOutputStream();

    @Before
    public void setUp() throws Exception {
        System.setOut(new PrintStream(outContent));
        System.setErr(new PrintStream(errContent));
    }

    @After
    public void cleanUp() {
        System.setOut(null);
        System.setErr(null);
    }

    @Test(expected = NullPointerException.class)
    public void testProcessArgs_null() {
        DaikonIntegration.processArgs(null);
    }

    @Test(expected = NullPointerException.class)
    public void testProcessArgs_nullArray() {
        String[] args = new String[1];
        DaikonIntegration.processArgs(args);
    }

    @Test
    public void testProcessArgs_invalidOptions() {
        String[] args = { "-a", "-d", "-f" };

        DaikonIntegration.processArgs(args);

        // FIXME Write proper assertion
        // assertFalse(errContent.toString().contains("Undefined option"));
    }

    @Test
    public void testProcessArgs_validOptions() {
        String[] args1 = { "--prefix=\"pt.um\"", "--inv-file=\"inv_file\"",
                "--heap-size=\"1024m\"", "target" };

        DaikonIntegration.processArgs(args1);

        assertEquals("\"pt.um\"", DaikonIntegration.getProjectPrefix());
        assertEquals("\"inv_file\"", DaikonIntegration.getInvFileName());
        assertEquals("\"1024m\"", DaikonIntegration.getHeapSize());
    }

    @Test(expected = NullPointerException.class)
    public void testSetUpChicory_null() {
        DaikonIntegration.setUpChicory(null, null, null, null);
    }

    @Test
    public void testSetUpChicory_nullOptions() {
        String[] target = { "target" };
        String[] expected = { "--daikon", "target" };
        String[] actual = DaikonIntegration.setUpChicory(null, null, null,
                target);

        assertArrayEquals(expected, actual);
    }

    @Test
    public void testSetUpChicory_someOptions() {
        String[] target = { "target" };
        ArrayList<String> expectedList = Lists.newArrayList();
        expectedList.add("--daikon");
        expectedList.add("--ppt-select-pattern=pt.um");
        expectedList.add("--heap-size=128m");
        expectedList.add("--dtrace-file=inv.dtrace.gz");
        expectedList.add("target");

        String[] expected = new String[expectedList.size()];
        expected = expectedList.toArray(expected);
        String[] actual = DaikonIntegration.setUpChicory("pt.um", "128m",
                "inv", target);

        assertArrayEquals(expected, actual);
    }

    @Test
    public void testGetSetInvariantMap() {
        PptMap map = mock(PptMap.class);

        DaikonIntegration.setInvariantsMap(map);

        assertEquals(map, DaikonIntegration.getInvariantsMap());
    }

    @Test
    @InvocationCount(10)
    public void testGetSetProjectPrefix(
            @Pattern(regexp = "[a-z0-9.]*") String projectPrefix) {
        DaikonIntegration.setProjectPrefix(projectPrefix);

        assertEquals(projectPrefix, DaikonIntegration.getProjectPrefix());
    }

    @Test
    @InvocationCount(10)
    public void testGetSetHeapSize(@Pattern (regexp= "[\\d]*m") String heapSize) {
        DaikonIntegration.setHeapSize(heapSize);

        assertEquals(heapSize, DaikonIntegration.getHeapSize());
    }

    @Test
    @InvocationCount(10)
    public void testGetSetInvDileName(String invFileName) {
        DaikonIntegration.setInvFileName(invFileName);

        assertEquals(invFileName, DaikonIntegration.getInvFileName());
    }
    
    @Test
    public void testGetSetRemainingArgs() {
        String[] args = {"a","b","c"};
        DaikonIntegration.setRemainingArgs(args);

        assertArrayEquals(args, DaikonIntegration.getRemainingArgs());
    }
}
